package com.wanxi.dangdang.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.wanxi.dangdang.common.OrderStateCode;
import com.wanxi.dangdang.mapper.OrderMapper;
import com.wanxi.dangdang.model.dto.COrderDto;
import com.wanxi.dangdang.model.dto.OrderDelayDto;
import com.wanxi.dangdang.model.pojo.Message;
import com.wanxi.dangdang.model.pojo.Order;
import com.wanxi.dangdang.model.pojo.OrderDetails;
import com.wanxi.dangdang.model.vo.*;
import com.wanxi.dangdang.receiver.MessageReceiver;
import com.wanxi.dangdang.scheduler.OrderCheckScheduler;
import com.wanxi.dangdang.service.OrderService;
import com.wanxi.dangdang.service.ScenicService;
import com.wanxi.dangdang.util.GenerateOrderNoUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Service("orderService")
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private ScenicService scenicService;

    @Autowired
    private MessageReceiver messageReceiver;

    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

    /**
     * 订单分页查询
     *
     * @param pageNum  当前页
     * @param pageSize 查询多少条
     * @return
     */
    @Override
    public PageInfo findPage(Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<Order> orderList = orderMapper.findPage();
        return new PageInfo<>(orderList);
    }

    /**
     * 分销商订单分页查询
     *
     * @param pageNum  当前页码
     * @param pageSize 每页显示记录数
     * @param storeId  分销商ID
     * @return
     */
    @Override
    public PageInfo findDistributorOrderPage(Integer pageNum, Integer pageSize, Long storeId) {
        PageHelper.startPage(pageNum, pageSize);
        List<Order> orderList = orderMapper.findDistributorOrderPage(storeId);
        return new PageInfo<>(orderList);
    }

    /**
     * 通过订单id查询订单信息和出行人信息
     *
     * @param id 订单id
     * @return
     */
    @Transactional
    @Override
    public OrderPo findById(Long id) {
        Order orderById = orderMapper.findOrderById(id);
        List<OrderDetails> orderDetailsList = orderMapper.findOrderDetailsById(id);
        OrderPo orderPo = new OrderPo();
        if (orderById != null) {
            BeanUtils.copyProperties(orderById, orderPo);
            orderPo.setOrderDetailsList(orderDetailsList);
        }
        return orderPo;
    }

    /**
     * 微信用户生成订单
     *
     * @param orderPo
     */
    @Transactional
    @Override
    public String add(OrderPo orderPo) {
        orderPo.setOrderNumber(GenerateOrderNoUtil.getOrderNo());
        orderPo.setCreateTime(new Date());
        orderPo.setUpdateTime(new Date());
        orderPo.setPrice(calculateTotalPrice(orderPo.getScenicId(),orderPo.getOrderDetailsList()));//计算订单总价
//        orderPo.setPrice(new BigDecimal(String.valueOf(orderPo.getPrice().multiply(new BigDecimal(orderPo.getPoll())))));//计算订单总价
        Double commissionRateByScenicId = scenicService.findCommissionRateByScenicId(orderPo.getScenicId());//佣金比例
        orderPo.setCommissionRate(commissionRateByScenicId);//设置佣金比例
        orderPo.setCommission(new BigDecimal(String.valueOf(orderPo.getPrice().multiply(new BigDecimal(commissionRateByScenicId)))));//计算佣金
//        orderPo.setCommission(new BigDecimal(String.valueOf(orderPo.getPrice().multiply(new BigDecimal(orderPo.getCommissionRate())))));//计算佣金
//      减去库存 第一参数：景区ID ，第二参数：出行日期时间戳
        // 生成出行日期库存，出行日期时间戳转换须修正
        long tripDate = orderPo.getTripDate().getTime();
        //查看库存是否充足
        Integer repertory = scenicService.findRepertory(orderPo.getScenicId(), tripDate);
        if (repertory > orderPo.getPoll()) {
//          修改对应表中出行日期库存记录
            boolean b = scenicService.reduceRepertory(orderPo.getScenicId(), tripDate, orderPo.getPoll());
            // 再次判断库存
            if (!b) {
                return "预定失败，库存不足";
            }
            //生成订单
            orderMapper.addInToOrder(orderPo);
            Long orderId = orderPo.getId();
            //生成随行人订单详情
            orderMapper.addInToOrderDetails(orderPo.getOrderDetailsList(), orderId);
            // 创建延时队列
            DelayQueue queue = new DelayQueue<>();
            OrderDelayDto orderDelayDto = new OrderDelayDto();
            orderDelayDto.setId(orderId);
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.MINUTE, 30);//过期时间30分钟
            orderDelayDto.setExpirationTime(calendar.getTime());
            //运行线程
            ExecutorService exec = Executors.newFixedThreadPool(1);
            exec.execute(new OrderCheckScheduler(queue));
            //往队列中放入数据
            queue.offer(orderDelayDto);
            exec.shutdown();
            return "预定成功，请在30分钟内尽快支付";
        }
        return "预定失败，库存不足";
    }

    /**
     * 计算订单总价
     * @param scenicId 景区id
     * @param orderDetailsList 出行人列表
     * @return
     */
    public BigDecimal calculateTotalPrice(Long scenicId,List<OrderDetails> orderDetailsList){
        ScenicFindByIdVO byId = scenicService.findById(scenicId);
        BigDecimal salesPrice = byId.getSalesPrice();
        BigDecimal price = new BigDecimal(0);
        for (OrderDetails orderDetails : orderDetailsList) {
            String ticketType = orderDetails.getTicketType();
            if (ticketType.equals("1")) {
                price = price.add(salesPrice);
            }else {
                price = price.add(salesPrice.multiply(new BigDecimal(0.5)));
            }
        }
        return price;
    }

    /**
     * 微信用户进行支付
     *
     * @param id
     */
    @Transactional
    @Override
    public String payMoney(Long id) {
        OrderStateVo orderStateVo = new OrderStateVo();
        orderStateVo.setId(id);
        Order orderById = orderMapper.findOrderById(id);
        if (orderById.getOrderState().equals(OrderStateCode.UNPAID.getCode())) {
            orderStateVo.setOrderState(OrderStateCode.PAID.getCode());
            orderMapper.updateOrderState(orderStateVo);
//        orderMapper.payMoney(id,OrderStateCode.PAID.getCode());
            // 当用户支付完成后对该景区门票的销量进行增加
            scenicService.increaseSale(orderById.getScenicId(), orderById.getPoll());
            // 支付完成后通过邮件方式告诉用户订单信息
            List<String> toUsers = new ArrayList<>();
            toUsers.add(orderById.getEmail());
            String tripDate = simpleDateFormat.format(orderById.getTripDate());
            String text = orderById.getRealName() + "你好，你在" + tripDate + "去往" + orderById.getScenicName() + "的订单已经支付成功。";
            encapsulateMail(toUsers, text);
            return "支付成功";
        }
        return "支付失败";
    }

    /**
     * 封装邮件信息
     *
     * @param toUsers 收件人
     * @param text    发送内容
     */
    public void encapsulateMail(List<String> toUsers, String text) {
        Message message = new Message();
        message.setSubject("当当旅游分销平台");
        message.setToUsers(toUsers);
        message.setText(text);
        messageReceiver.send(message);
    }

    /**
     * 修改订单状态
     *
     * @param orderStateVo 订单id，订单状态，负责人id
     */
    @Transactional
    @Override
    public String updateOrderState(OrderStateVo orderStateVo) {
        int i = orderMapper.updateOrderState(orderStateVo);
        if (i > 0) {
            Order orderById = orderMapper.findOrderById(orderStateVo.getId());
            List<String> toUsers = new ArrayList<>();
            toUsers.add(orderById.getEmail());
            String tripDate = simpleDateFormat.format(orderById.getTripDate());
            String text = orderById.getRealName() + "你好，你在" + tripDate + "去往" + orderById.getScenicName() + "的订单状态为：" + OrderStateCode.getOrderStateCodeMsg(orderById.getOrderState());
            encapsulateMail(toUsers, text);
            return "修改成功";
        }
        return "修改失败";
    }

    /**
     * 管理员通过订单状态查询分页
     *
     * @param orderState 订单状态
     * @param pageNum    当前页
     * @param pageSize   查询多少条
     * @return
     */
    @Override
    public PageInfo findByOrderState(Integer orderState, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<Order> byOrderState = orderMapper.findByOrderState(orderState);
        return new PageInfo<>(byOrderState);
    }

    /**
     * 管理员通过订单号查询订单
     *
     * @param orderNumber
     * @return
     */
    @Override
    public Order findByOrderNumber(String orderNumber) {
        Order byOrderNumber = orderMapper.findByOrderNumber(orderNumber);
        return byOrderNumber;
    }

    /**
     * 管理员认领订单
     *
     * @param orderStateVo
     */
    @Override
    public void updateStatusAndAdminId(OrderStateVo orderStateVo) {
        orderMapper.updateStatusAndAdminId(orderStateVo);
    }

    /**
     * 管理员查看自己的已认领订单分页
     *
     * @param adminId
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo findByAdminId(Long adminId, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<Order> byAdminId = orderMapper.findByAdminId(adminId);
        return new PageInfo<>(byAdminId);
    }

    /**
     * 订单数量图表查询
     *
     * @return
     */
    @Transactional
    @Override
    public HashMap<String, Integer> findAllOrdersByDate() {
        HashMap<String, Integer> allOrders = new HashMap<>();
        Date today = new Date();
        Calendar now = Calendar.getInstance();
        now.setTime(today);
        for (int i = 0; i < 7; i++) {
            int allOrdersByDate = orderMapper.findAllOrdersByDate(now.getTime());
            allOrders.put(DateFormatUtils.format(now.getTime(), "MM-dd"), allOrdersByDate);
            now.add(Calendar.DAY_OF_MONTH, -1);//往前推一天
        }
        return allOrders;
    }

    /**
     * 销售金额图表查询
     *
     * @return
     */
    @Transactional
    @Override
    public HashMap<String, BigDecimal> findPriceTotalByDate() {
        HashMap<String, BigDecimal> priceTotal = new HashMap<>();
        Date today = new Date();
        Calendar now = Calendar.getInstance();
        now.setTime(today);
        for (int i = 0; i < 7; i++) {
            BigDecimal priceTotalByDate = orderMapper.findPriceTotalByDate(now.getTime());
            priceTotal.put(DateFormatUtils.format(now.getTime(), "MM-dd"), priceTotalByDate);
            now.add(Calendar.DAY_OF_MONTH, -1);
        }
        return priceTotal;
    }

    /**
     * 微信用户查看自己在当前门店的订单
     *
     * @param cUserAndStoreOrderVo 门店id，微信id，分页参数
     * @return
     */
    @Transactional
    @Override
    public PageInfo findByStoreIdAndWeChatId(CUserAndStoreOrderVo cUserAndStoreOrderVo) {
        PageHelper.startPage(cUserAndStoreOrderVo.getPageNum(), cUserAndStoreOrderVo.getPageSize());
        List<Order> byStoreIdAndWeChatId = orderMapper.findByStoreIdAndWeChatId(cUserAndStoreOrderVo.getStoreId(), cUserAndStoreOrderVo.getWeChatId());
        List<COrderDto> cOrderDtoList = new LinkedList<>();
        for (Order order : byStoreIdAndWeChatId) {
            COrderDto cOrderDto = new COrderDto();
            BeanUtils.copyProperties(order,cOrderDto);
            ScenicFindByIdVO byId = scenicService.findById(order.getScenicId());
            cOrderDto.setCenterPicture("http://qyuhitnjl.hn-bkt.clouddn.com/"+byId.getCenterPicture());
            cOrderDto.setOrderState(OrderStateCode.getOrderStateCodeMsg(order.getOrderState()));
            cOrderDtoList.add(cOrderDto);
        }
        return new PageInfo<>(cOrderDtoList);
    }

    /**
     * 微信用户查看自己在当前门店的不同状态的订单
     *
     * @param cUserOrderVo 门店id，微信id，订单状态，分页参数
     * @return
     */
    @Transactional
    @Override
    public PageInfo findByStoreIdAndWeChatIdAndStatus(CUserOrderVo cUserOrderVo) {
        PageHelper.startPage(cUserOrderVo.getPageNum(), cUserOrderVo.getPageSize());
        List<Order> byStoreIdAndWeChatIdAndStatus = orderMapper.findByStoreIdAndWeChatIdAndStatus(cUserOrderVo.getStoreId(), cUserOrderVo.getWeChatId(), cUserOrderVo.getOrderState());
        List<COrderDto> cOrderDtoList = new LinkedList<>();
        for (Order order : byStoreIdAndWeChatIdAndStatus) {
            COrderDto cOrderDto = new COrderDto();
            BeanUtils.copyProperties(order,cOrderDto);
            ScenicFindByIdVO byId = scenicService.findById(order.getScenicId());
            cOrderDto.setCenterPicture("http://qyuhitnjl.hn-bkt.clouddn.com/"+byId.getCenterPicture());
            cOrderDto.setOrderState(OrderStateCode.getOrderStateCodeMsg(order.getOrderState()));
            cOrderDtoList.add(cOrderDto);
        }
        return new PageInfo<>(cOrderDtoList);
    }

    /**
     * 微信用户申请退款
     *
     * @param refundVo
     */
    @Transactional
    @Override
    public String refund(RefundVo refundVo) {
        Order orderById = orderMapper.findOrderById(refundVo.getId());
        Integer orderState = orderById.getOrderState();
        if (orderState.equals(OrderStateCode.PAID.getCode())
                || orderState.equals(OrderStateCode.ISSUING.getCode())
                || orderState.equals(OrderStateCode.TICKETS_HAVE_BEEN_ISSUED.getCode())) {
            orderMapper.refund(refundVo.getId(), refundVo.getRemark(), OrderStateCode.PENDING_REFUND.getCode());
            List<String> toUsers = new ArrayList<>();
            toUsers.add(orderById.getEmail());
            String tripDate = simpleDateFormat.format(orderById.getTripDate());
            String text = orderById.getRealName() + "你好，你在" + tripDate + "去往" + orderById.getScenicName() + "的订单申请退款成功，管理员正在加急审核中，请耐心等待。";
            encapsulateMail(toUsers, text);
            return "申请成功";
        }
        return "申请失败";
    }

    /**
     * 订单超时未支付自动取消
     *
     * @param id
     */
    @Transactional
    @Override
    public void autoCancelOrder(Long id) {
        Order orderById = orderMapper.findOrderById(id);
        if (orderById.getOrderState().equals(OrderStateCode.UNPAID.getCode())) {
            OrderStateVo orderStateVo = new OrderStateVo();
            orderStateVo.setId(id);
            orderStateVo.setOrderState(OrderStateCode.CANCELLED.getCode());
            orderMapper.updateOrderState(orderStateVo);
            //修改出行人状态为停用
            orderMapper.updateOrderDetailsStatus(orderStateVo.getId());
            //恢复库存
            scenicService.addRepertory(orderById.getScenicId(), orderById.getTripDate().getTime(), orderById.getPoll());
            List<String> toUsers = new ArrayList<>();
            toUsers.add(orderById.getEmail());
            String tripDate = simpleDateFormat.format(orderById.getTripDate());
            String text = orderById.getRealName() + "你好，你在" + tripDate + "去往" + orderById.getScenicName() + "的订单超时未支付，已被自动取消。";
            encapsulateMail(toUsers, text);
        }
    }

    /**
     * 微信用户申请取消订单
     *
     * @param cancelOrderVo
     * @return
     */
    @Transactional
    @Override
    public String cancelOrder(CancelOrderVo cancelOrderVo) {
        Order orderById = orderMapper.findOrderById(cancelOrderVo.getId());
        Integer orderStateById = orderById.getOrderState();
        if (orderStateById.equals(OrderStateCode.UNPAID.getCode())) {
            orderMapper.cancelOrder(cancelOrderVo.getId(), cancelOrderVo.getWeChatId(), OrderStateCode.CANCELLED.getCode());
            //修改出行人状态为停用
            orderMapper.updateOrderDetailsStatus(cancelOrderVo.getId());
            // 恢复库存表当前景区在出行日期当天的库存
            scenicService.addRepertory(orderById.getScenicId(), orderById.getTripDate().getTime(), orderById.getPoll());
            List<String> toUsers = new ArrayList<>();
            String tripDate = simpleDateFormat.format(orderById.getTripDate());
            toUsers.add(orderById.getEmail());
            String text = orderById.getRealName() + "你好，你在" + tripDate + "去往" + orderById.getScenicName() + "的订单取消成功。";
            encapsulateMail(toUsers, text);
            return "取消成功";
        }
        return "取消失败";
    }

    /**
     * 通过订单ID查询所属订单详情信息
     *
     * @param id 订单ID
     * @return
     */
    @Transactional
    @Override
    public Map<String, Object> findDetailsByOrderId(Long id) {
        Map<String, Object> map = new HashMap<>();
        /**
         * 1、通过订单Id查询订单信息
         * 2、通过订单Id查询所属订单随行人信息
         */
        Order order = orderMapper.findOrderById(id);
        Map<String, Object> orderMap = encapsulationOrder(order);
        List<OrderDetails> orderDetailsList = orderMapper.findOrderDetailsById(id);
        map.put("order", orderMap);
        map.put("orderDetails", orderDetailsList);
        return map;
    }

    /**
     * 封装前端需要的信息
     *
     * @param order 订单信息
     * @return
     */
    private Map<String, Object> encapsulationOrder(Order order) {
        Map<String, Object> map = new HashMap<>();
        map.put("scenicName", order.getScenicName());
        map.put("tripDate", order.getTripDate().getTime());
        map.put("poll", order.getPoll());
        map.put("commission", order.getCommission());
        map.put("realName", order.getRealName());
        map.put("phone", order.getPhone());
        map.put("idCard", order.getIdCard());
        map.put("email", order.getEmail());
        return map;
    }

    /**
     * 分销商通过出行日期查询
     *
     * @param pageNum
     * @param pageSize
     * @param tripDate
     * @param storeId
     * @return
     */
    @Override
    public PageInfo findDistributorOrderByDate(Integer pageNum, Integer pageSize, Date tripDate, Long storeId) {
        PageHelper.startPage(pageNum, pageSize);
        String userTripDate = DateFormatUtils.format(tripDate, "yyyy-MM-dd");
        List<Order> orderList = orderMapper.findDistributorOrderByDate(userTripDate, storeId);
        return new PageInfo<>(orderList);
    }

    /**
     * 返回当天卖出的总票数
     *
     * @param scenicId 景区id
     * @param tripDate 出行日期
     * @return
     */
    @Override
    public int countOrders(Long scenicId, Date tripDate) {
        return orderMapper.countOrders(scenicId, tripDate);
    }

    /**
     * 管理员确认是否退款
     *
     * @param orderStateVo 订单id，订单状态，负责人id
     */
    @Transactional
    @Override
    public String confirmRefund(OrderStateVo orderStateVo) {
        Order orderById = orderMapper.findOrderById(orderStateVo.getId());
        List<String> toUsers = new ArrayList<>();
        toUsers.add(orderById.getEmail());
        if (orderById.getOrderState().equals(OrderStateCode.PENDING_REFUND.getCode())
                && orderStateVo.getOrderState().equals(OrderStateCode.REFUNDED.getCode())) {
            orderMapper.updateOrderState(orderStateVo);
            //修改出行人状态为停用
            orderMapper.updateOrderDetailsStatus(orderStateVo.getId());
            // 退款成功后恢复库存表当前景区在出行日期当天的库存
            scenicService.addRepertory(orderById.getScenicId(), orderById.getTripDate().getTime(), orderById.getPoll());
            String tripDate = simpleDateFormat.format(orderById.getTripDate());
            String text = orderById.getRealName() + "你好，你在" + tripDate + "去往" + orderById.getScenicName() + "的订单退款成功,请注意查收";
            encapsulateMail(toUsers, text);
            return "退款成功";
        }
        orderStateVo.setOrderState(OrderStateCode.REFUND_FAILED.getCode());
        orderMapper.updateOrderState(orderStateVo);
        String tripDate = simpleDateFormat.format(orderById.getTripDate());
        String text = orderById.getRealName() + "你好，你在" + tripDate + "去往" + orderById.getScenicName() + "的订单退款失败，详情请联系管理人员";
        encapsulateMail(toUsers, text);
        return "退款失败，具体原因请联系管理员。";

    }

    /**
     * c 端用户通过id查询详情
     *
     * @param id
     * @param weChatId
     * @return
     */
    @Override
    public OrderPo findCOrderById(Long id, String weChatId) {
        OrderPo orderPo = new OrderPo();
        Order cOrderById = orderMapper.findCOrderById(id, weChatId);
        ScenicFindByIdVO byId = scenicService.findById(cOrderById.getScenicId());
        orderPo.setCenterPicture("http://qyuhitnjl.hn-bkt.clouddn.com/"+byId.getCenterPicture());
        List<OrderDetails> orderDetailsList = orderMapper.findOrderDetailsById(id);
        if (cOrderById != null) {
            BeanUtils.copyProperties(cOrderById, orderPo);
            orderPo.setOrderDetailsList(orderDetailsList);
        }
        return orderPo;
    }

    /**
     * 通过订单ID和分销商ID查询订单详情
     *
     * @param id
     * @param storeId
     * @return
     */
    @Override
    public Map<String, Object> findBDetailsByOrderId(Long id, Long storeId) {
        Map<String, Object> map = new HashMap<>();
        /**
         * 1、通过订单Id和分销商ID查询订单信息
         * 2、通过订单Id查询所属订单随行人信息
         */
        Order order = orderMapper.findBOrderById(id, storeId);
        Map<String, Object> orderMap = encapsulationOrder(order);
        List<OrderDetails> orderDetailsList = orderMapper.findOrderDetailsById(id);
        map.put("order", orderMap);
        map.put("orderDetails", orderDetailsList);
        return map;
    }
}
